package one.stand.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.jmp.base.SecurityUserApi;
import com.jmp.base.dto.*;
import com.jmp.feign.AccountFeign;
import com.jmp.security.grant.wx.WxAppRquestDetail;
import com.jmp.security.grant.wx.WxLoginService;
import lombok.extern.slf4j.Slf4j;
import one.stand.advice.ResultEnum;
import one.stand.dto.WechatLoginDto;
import one.stand.dto.WechatUserInfoDto;
import one.stand.entity.TokenEntity;
import one.stand.enums.LoginEnum;
import one.stand.mapper.SecurityClientMapperExt;
import one.stand.model.*;
import one.stand.service.BusinessCardBaseService;
import one.stand.service.SecurityAuthService;
import one.stand.service.UserService;
import one.stand.service.user.TokenService;
import one.stand.service.user.UserAdminService;
import one.stand.util.AssertUtil;
import one.stand.util.RequestContext;
import one.stand.util.RequestContextHolder;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;

@RestController
@Slf4j
public class SecurityUserController implements SecurityUserApi {
    @Autowired
    private AccountFeign accountFeign;

    @Autowired
    private UserAdminService userAdminService;
    @Autowired
    private BusinessCardBaseService businessCardBaseService;
    @Autowired
    private TokenService tokenService;
    @Autowired
    private WxLoginService wxLoginService;

    @Autowired
    private SecurityClientMapperExt securityClientMapperExt;
    @Autowired
    private SecurityAuthService securityAuthService;
    @Autowired
    private UserService userService;

    @Override
    public ResultModel<TokenEntity> loginInfo(@RequestBody String token) {
        TokenEntity tokenEntity = tokenService.getInfo(token);
        if (Objects.isNull(tokenEntity)) {
            tokenEntity = tokenService.getAdminInfo(token);
        }
        return ResultModel.success(tokenEntity);
    }

    @Override
    @Transactional
    public ResultModel userBindWx(@RequestBody SecurityUserBindWxRequest request) {

        WxAppRquestDetail.AppOauth appOauth = getWxInfo(request.getAppOauth());
        WechatUserInfoDto userInfoDto = JSONObject.parseObject(appOauth.getUserInfo(), WechatUserInfoDto.class);
        if (StringUtils.isBlank(appOauth.getUnionid()) && Objects.nonNull(userInfoDto)) {
            appOauth.setUnionid(userInfoDto.getUnionid());
        }

        bindWx(appOauth.getOpenId(), appOauth.getUnionid(), request.getUserId());

        return ResultModel.success();
    }

    @Override
    public ResultModel userBindWx2(@RequestBody SecurityUserBindWx2Request request) {

        AssertUtil.nonNull(request.getClientEnum(), ResultEnum.PARAM_CHECK);
        AssertUtil.nonNull(request.getCode(), ResultEnum.PARAM_CHECK);
        SecurityClient securityClient = securityClientMapperExt.selectByName(request.getClientEnum().getCode());
        AccountAppIdRequest accountCompanyKeyRequest = AccountAppIdRequest.builder()
                .appId(securityClient.getWxAppId())
                .build();
        ResultModel<AccountResponse> accountResponseResultModel = accountFeign.getByAppId2(accountCompanyKeyRequest);
        AssertUtil.isTrue(accountResponseResultModel);
        WechatLoginDto loginDto = wxLoginService.loginBack(request.getCode(), accountResponseResultModel.getData().getAppId(), accountResponseResultModel.getData().getAppSecret());

        bindWx(loginDto.getOpenId(), loginDto.getUnionId(), request.getUserId());

        return ResultModel.success();
    }

    @Override
    @Transactional
    public ResultModel userBindPhone(@RequestBody SecurityUserBindPhoneRequest request) {
        User user = userService.getByPhone(request.getPhone(), null);
        if (Objects.nonNull(user)
                && !user.getUserId().equals(request.getUserId())
                && StringUtils.isBlank(user.getUnionid())) {//删除重复用户
            BusinessCard businessCard = businessCardBaseService.getByUserId(user.getUserId());
            AssertUtil.isNull(businessCard, "当前微信已绑定");
            userService.deleteById(user.getUserId());
            tokenService.remove(Lists.newArrayList(Long.valueOf(user.getUserId())));
        }

        User userUpdate = new User();
        userUpdate.setUserId(request.getUserId());
        userUpdate.setPhone(request.getPhone());
        userService.update(userUpdate);
        return ResultModel.success();
    }

    @Override
    public ResultModel<SecurityUserBindWxPhoneResponse> userBindWxPhone(@RequestBody SecurityUserBindWxPhoneRequest request) {
        if (org.springframework.util.StringUtils.isEmpty(request.getPhoneData()) || org.springframework.util.StringUtils.isEmpty(request.getPhoneIv())) {
            return ResultModel.checkParamFail();
        }
        WechatUserInfoDto userInfoDto = wxLoginService.getUserInfo(request.getPhoneData(), request.getSessionKey(), request.getPhoneIv());
        log.info("解析手机号：{}", userInfoDto);

        String phone = userInfoDto.getPurePhoneNumber();
        User userUpdate = new User();
        userUpdate.setUserId(request.getUserId());
        userUpdate.setPhone(phone);
        userService.update(userUpdate);

        SecurityUserBindWxPhoneResponse response = SecurityUserBindWxPhoneResponse.builder().phone(phone).build();
        return ResultModel.success(response);
    }

    @Override
    public ResultModel<SecurityAuthSaveVo> authSave(@RequestBody SecurityAuthSaveDto request) {
        SecurityAuth securityAuth = new SecurityAuth();
        securityAuth.setId(request.getId());
        securityAuth.setType(request.getType());
        securityAuth.setTypeId(request.getTypeId());
        securityAuth.setTypeAuth(request.getTypeAuth());
        securityAuth.setStartTime(request.getStartTime());
        securityAuth.setEndTime(request.getEndTime());
        securityAuthService.save(securityAuth);

        SecurityAuthSaveVo vo = SecurityAuthSaveVo.builder().build();
        return ResultModel.success(vo);
    }

    @Override
    public ResultModel<SecurityAuthListVo> authList(@RequestBody SecurityAuthListDto request) {
        List<SecurityAuthListVo.Auth> authList = Lists.newArrayList();
        for (TypeAuth typeAuth : TypeAuth.values()) {
            ResultModel<SecurityAuthCheckVo> authCheckVoResultModel = authCheck(SecurityAuthCheckDto.builder()
                    .type(request.getType())
                    .typeId(request.getTypeId())
                    .typeAuth(typeAuth.getCode())
                    .build());
            authList.add(SecurityAuthListVo.Auth.builder()
                    .typeAuthName(typeAuth.getName())
                    .typeAuth(typeAuth.getCode())
                    .authCheck(BooleanUtils.toInteger(authCheckVoResultModel.getData().isAuthCheck()))
                    .id(authCheckVoResultModel.getData().getId())
                    .startTime(authCheckVoResultModel.getData().getStartTime())
                    .endTime(authCheckVoResultModel.getData().getEndTime())
                    .build());
        }

        SecurityAuthListVo vo = SecurityAuthListVo.builder()
                .authList(authList)
                .build();
        return ResultModel.success(vo);
    }

    @Override
    public ResultModel<SecurityAuthCheckVo> authCheck(@RequestBody SecurityAuthCheckDto request) {
        SecurityAuth securityAuth = securityAuthService.get(request.getType(), request.getTypeId(), request.getTypeAuth());
        Date now = new Date();
        SecurityAuthCheckVo vo = SecurityAuthCheckVo.builder()
                .authCheck(now.compareTo(securityAuth.getStartTime()) >= 0 && now.compareTo(securityAuth.getEndTime()) <= 0)
                .id(securityAuth.getId())
                .startTime(securityAuth.getStartTime())
                .endTime(securityAuth.getEndTime())
                .build();
        return ResultModel.success(vo);
    }

    private WxAppRquestDetail.AppOauth getWxInfo(Map<String, Object> appOauth) {
        return WxAppRquestDetail.AppOauth.builder()
                .unionid(MapUtils.getString(appOauth, "unionid"))
                .sessionKey(MapUtils.getString(appOauth, "access_token"))
                .openId(MapUtils.getString(appOauth, "openId"))
                .userInfo(JSON.toJSONString(MapUtils.getMap(appOauth, "userInfo")))
                .build();
    }

    private void bindWx(String openId, String unionid, Integer userId) {
        RequestContext requestContext = RequestContextHolder.getRequestContext();
        LoginEnum loginEnum = LoginEnum.getByCode(requestContext.getUser().getLoginProgramName());

        User user = userService.getByWx(unionid, loginEnum, requestContext.getUser().getCompanyKey(), openId);

        if (Objects.nonNull(user) && !user.getUserId().equals(userId)) {
            User optUser = userAdminService.getByUserId(userId);
            if (StringUtils.isBlank(optUser.getUnionid())) {//删除重复用户
                BusinessCard businessCard = businessCardBaseService.getByUserId(userId);
                AssertUtil.isNull(businessCard, "当前微信已绑定");
                userService.deleteById(userId);
                tokenService.remove(Lists.newArrayList(Long.valueOf(userId)));

                //更新信息
                User userUpdate = new User();
                userUpdate.setUserId(user.getUserId());
                userUpdate.setPhone(optUser.getPhone());
                userService.update(userUpdate);

                userService.saveUserLoginWx(user.getUserId(), loginEnum.getAccountType(), requestContext.getUser().getCompanyKey(), openId);
            }
        } else {
            //更新信息
            user = new User();
            user.setUserId(userId);
            user.setUnionid(unionid);
            userService.update(user);

            userService.saveUserLoginWx(user.getUserId(), loginEnum.getAccountType(), requestContext.getUser().getCompanyKey(), openId);
        }
    }
}
